﻿#region Header

/*
Behavioral Rating of Dancing Human Crowds based on Motion Patterns
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using Emgu.CV;
using Emgu.CV.Structure;
using paravili.Services;
using paravili.Steps;

#endregion

namespace paravili.CaptureSources {
	/// <summary>
	/// Represents a capture source that gets the images data from the images located
	/// on a dictionary on the physical harddisk
	/// </summary>
	public class ImagesFromDiskAsCaptureSource : ICapture, IDisposableCaptureSource {
		#region Public Properties

		[ConfigurabelStringValue(Name = "Path of the images")]
		public string DictionaryImagesPath { get; set; }

		[ConfigurableNumericValue(Name = "Scale Factor", RangeFrom = 0, RangeTo = 3)]
		public int ScaleFactor { get; set; }

		[ConfigurabelStringValue(Name = "Name of the datasource")]
		public string Name { get; set; }

		#endregion

		#region Public Methods

		public ImagesFromDiskAsCaptureSource() {
			ScaleFactor = 2;
		}

		#endregion

		#region Private Methods

		private void Worker() {
			while (m_isWorking) {
				if (m_storedImages.Count < PreloadFactor) {
					m_lock.AcquireWriterLock(Timeout.Infinite);
					m_storedImages.Enqueue(new Image<Bgr, byte>(m_imagesPath[(m_index++) % m_imagesPath.Length]));
					m_lock.ReleaseWriterLock();
				}
				else {
					Thread.Sleep(50);
				}
			}
			m_storedImages.Clear();
		}

		#endregion

		#region Private Fields

		private const int PreloadFactor = 20;
		private readonly ReaderWriterLock m_lock = new ReaderWriterLock();
		private readonly Queue<Image<Bgr, Byte>> m_storedImages = new Queue<Image<Bgr, byte>>();
		private string[] m_imagesPath;
		private int m_index;
		private bool m_isWorking;
		private Thread m_workerThread;

		#endregion

		#region ICapture Members

		public Image<Bgr, byte> QueryFrame() {
			while (m_storedImages.Count < 1) {
				Thread.Sleep(50);
			}
			//	m_lock.AcquireReaderLock(Timeout.Infinite);
			Image<Bgr, byte> img = m_storedImages.Dequeue();
			//	m_lock.ReleaseReaderLock();

			for (int i = 0; i < ScaleFactor; i++) {
				img = img.PyrDown();
			}
			return img;
		}

		public Image<Bgr, byte> QuerySmallFrame() {
			return QueryFrame().PyrDown();
		}

		#endregion

		#region IDisposableCaptureSource Members

		public Image<Bgr, byte> QueryImage() {
			return QueryFrame();
		}

		public void DoInit() {
			m_imagesPath = Directory.GetFiles(DictionaryImagesPath, "*.jpg");
			m_isWorking = true;
			m_workerThread = new Thread(Worker);
			m_workerThread.Start();
		}

		public void DoCleanUp() {
			m_isWorking = false;
			m_workerThread.Join();
		}

		public bool IsAvailable {
			get { return Directory.Exists(DictionaryImagesPath) && Directory.GetFiles(DictionaryImagesPath, "*.jpg").Length > 0; }
		}

		#endregion
	}
}